/** EN7894 Concurrent Programming Assign #1 Question 2a
 * 
 * Submitted By: 	Robert Lockyer (200534006)
 * 					Andrew Carter (200517548)
 * 
 * Date Due: May 28th, 2010
 */

package assign1;

import assign1.ItSummer;
import assign1.ItSummer.ItSumWorker;

public class ItSummer {

	int totalSum = 0;
	int numElementsInArray = 250;
	int PR = 25;
	
	int[] arrayToSum = new int[numElementsInArray];
	ItSumWorker[] workerThreads = new ItSumWorker[PR];

	
	private void initializeArray()
	{
		for(int i=0; i < numElementsInArray; ++i)
		{
			arrayToSum[i] = (int)(Math.random() * 1000);
		}
	}
	
	public void calculateSum()
	{
		int indicieWidth = numElementsInArray/PR;
		
		int curLowIndicie = 0;
		int curHighIndicie = indicieWidth - 1;
		
		/* Using the Concurrent Composition Rule:
		 * {totalSum = 0 ^ numElementsInArray=X ^ PR=Y ^ X/Y=E{NaturalNumbers} ^ arrayToSum=Z}
		 */
		for(int i=0; i < PR; ++i)
		{
			workerThreads[i] = new ItSumWorker(curLowIndicie, curHighIndicie);
			// co
			workerThreads[i].start(); // // (new parallel operations spawned here)
			
			curLowIndicie += indicieWidth;
			curHighIndicie += indicieWidth;
		}
		
		boolean allWorkersDone = false;
		while(!allWorkersDone)
		{
			allWorkersDone = true;
			for (ItSumWorker curWorker : workerThreads) {
				if(curWorker.isDone != true)
				{
					allWorkersDone = false;
					try {
						Thread.sleep(42);
					} catch (InterruptedException e) {}
					break;
				}
			}
		}
		// oc
		
		for (ItSumWorker curWorker : workerThreads) {
			// {curWorker.sum = sigma(j=lowIndicie; highIndicie; Z[j])}
			totalSum += curWorker.sum;
		}
		// Postconditions
		// {totalSum = sigma(i=0; X-1; Z[i])}
	}
	
	
	public class ItSumWorker extends Thread{
		
		private int lowIndicie;
		private int highIndicie;
		
		private boolean isDone = false;
		private int sum = 0;
		
		ItSumWorker(int lowerIndicie, int higherIndicie)
		{
			lowIndicie = lowerIndicie;
			highIndicie = higherIndicie;
		}
		
		@Override
		public void run() {
			doSum();
		}
		
		public boolean getIsDone()
		{
			return isDone;
		}
		
		public int getSum()
		{
			return sum;
		}

		private void doSum()
		{
			// {sum = 0 ^ lowIndicie = j ^ highIndicie = k}
			for(int i = lowIndicie; i <= highIndicie; ++i) // LI: sum = sigma(y=j; i-1; Z[y])
			{
				sum += arrayToSum[i]; // sum = sigma(y=j; i; Z[y])
			}
			// {sum = sigma(y=j; i-1; Z[y]) ^ i = k}
			
			isDone = true;
		}
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		ItSummer glue = new ItSummer();
		
		glue.initializeArray();
		
		int sequentialSum = 0;
		// print values of array
		for (Integer intToPrint : glue.arrayToSum) {
			System.out.println(intToPrint.toString());
			sequentialSum += intToPrint;
		}
		System.out.println("Sequential Sum = " + sequentialSum);
		
		glue.calculateSum();
		System.out.println("Concurrent Sum = " + glue.totalSum);
	}
}
